/*
    Contact info:
    bhepple@freeshell.org
    http://bhepple.freeshell.org/scrmgr

    Copyright (C) 1991-2008 Bob Hepple

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; see the file COPYING.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.

*/
/* SCRMGR data cleaner - pulls data through the screens and writes it out.
   This ensures that no fields are missing and that maxlen fields are
   honoured */

#include <stdio.h>
#include <getopt.h>
#include <setjmp.h>
#include "smlib.h"

CHAR *smclean_rcsid(void) {
    return("$Id: smclean.c,v 1.6 2008/02/19 13:15:50 bhepple Exp $");
}

static CHAR	*progname, pname[9];
static CHAR	rev_string[] = "$Revision: 1.6 $";
jmp_buf		NoMoreHeap;

static CHAR *usage_msg[] = {

"Pulls data through SCRMGR screens and writes it back to the file(s)",
"(or to stdout if there is no filename). This ensures that no fields",
"are missing and that field rules are obeyed.",
"",
"Backups of files are preserved in \"filename~\".",
"",
"screenfile : use screen file to define the data structure",
"screen     : only use the screen named \"screen-name\" from \"screenfile\".",
"datafile   : override data file(s) specified in \"screenfile\"",

NULL
};

CHAR regular_exp[100];
CHAR substitute[100];

void usage()
{
    CHAR **c;
    
    fprintf(stderr, "Revision %s of %s.\n", rev_string, pname);
    fprintf(stderr, "Usage: %s screenfile[:screen] [datafile [datafile ... ]]\n", pname);
    
    c = usage_msg;
    while (*c) {
        fputs(*c, stderr);
        fputc('\n', stderr);
        c++;
    }
    exit(2);
}

/* Stubs to be overidden if needed (at the moment, only if your application
   uses field triggers) */

f_ptr sm_get_field_trigger ARG1(SM_FIELD, field)
{
    return(NULL);
}

void sm_error_exit ARG1(CHAR *, msg)
{
    sm_term();
    fprintf(stderr, "%s\n", msg);
    
    exit(1);
}

int data_open ARG1(SM_SCREEN, screen)
{
    if (smdb_read_file(screen->filename, screen, sm_user_screens()->untabify))
        return(SM_ERROR);
    else
	return(0);
}

static void store_files ARG1(int, emergency)
{
    SM_SCREEN	*screenp, screen;
    
    for (screenp = sm_first_scr(sm_user_screens());
	 screenp && *screenp;
	 screenp = sm_next_scr(screenp)) {
	
	screen = *screenp;
	if (screen->filename)
	    smdb_write_file(screen->filename, screen, emergency);
    }
}

int main ARG2(int, argc, CHAR **, argv)
{
    static CHAR last_scr_filename[MAXPATHLEN + 1] = "",
		*screen_to_use;
    int		c;
    SM_SCREEN	*screenp, screen;

    /* Temporary back door */
    if (setjmp(NoMoreHeap)) {
        alloca(0);
        sm_error_exit(sm_mem_error);
    }

    progname = argv[0];
    fname(pname, progname);
    
    while ((c = getopt(argc, argv, "h?")) != EOF)
        switch (c) {
	    
                default:  
                    usage(); 
                    break;
        }
    
    if ((optind >= argc) || (strlen(argv[optind]) == 0))
        usage();
    else { /* Use first argument as screen file */
        if ((screen_to_use = strchr(argv[optind], ':')) != NULL)
            *screen_to_use++ = 0;
        strcpy(last_scr_filename, argv[optind++]);
    }

    sm_init(0, argc, argv);

#ifdef SM_DEBUG
    smio_flushinp();
#endif

    /* Go get screenfile */
    if (sm_fopen(sm_user_screens(), last_scr_filename) == SM_ERROR) {
        sm_error("Error reading screen file");
        sm_term();
        exit(1);
    }

    /* if a screen was given, delete all but that screen */
    for (screenp = sm_first_scr(sm_user_screens());
         screen_to_use && screenp && *screenp;) {
        screen = *screenp;
        if (strcmp(screen->screen_name, screen_to_use)) {
            sm_destroy_scr(screenp);
            screenp = sm_first_scr(sm_user_screens());
        } else {
            SM_FIELD	*fp;

            for (fp = sm_first_fld(*screenp);
                 fp && *fp;
                 fp = sm_next_fld(fp))
                (*fp)->master_screen_name = NULL; 
	        /* to allow simple edits to be done */

            screenp = sm_next_scr(screenp);
        }
    }

    screenp = sm_first_scr(sm_user_screens());
    if ((screenp == NULL) || (*screenp == NULL)) {
        if (screen_to_use)
            sm_error_exit("No such screen in that file!");
        else
            sm_error_exit("No screens in that file!");
    }
    
    /* Attach any data in filenames passed as arguments to consecutive
       screens */
    for (screenp = sm_first_scr(sm_user_screens());
         screenp && *screenp && (optind < argc); 
         screenp = sm_next_scr(screenp), optind++) {

        screen = *screenp;
        SM_ASSIGN(screen->filename, argv[optind]);
        data_open(screen);
    }

    /* Now open any files mentioned as defaults in the screenfile
       definition provided data has not already been read in for that file*/
    for (screenp = sm_first_scr(sm_user_screens());
         screenp && *screenp; 
         screenp = sm_next_scr(screenp)) {

        screen = *screenp;
        if (screen->filename && (screen->data == NULL))
            data_open(screen);
    }

    /* Now set default screen */
    screenp = sm_first_scr(sm_user_screens());
    screen = screenp? *screenp: NULL;

    /* Back door for when we run out of heap - horrible structure, but
       what can one do ?*/

    if (setjmp(NoMoreHeap)) {
        alloca(0);

        /* Prevent infinite loop */
        if (setjmp(NoMoreHeap)) {
            alloca(0);
            sm_error_exit(sm_mem_error);
        }

        sm_message(sm_mem_error);

        if (setjmp(NoMoreHeap)) {
            /* Oh boy - really serious! */
            alloca(0);
            sm_error_exit("Ran out of heap - file(s) were not saved! Sorry!");
        }

        store_files(1);
        alloca(0);

        if (setjmp(NoMoreHeap) == 0)
            sm_term();
        exit(1);
    }

    /* Now pull each data record through the screen ... */
    for (screenp = sm_first_scr(sm_user_screens()); 
         screenp && *screenp; 
         screenp = sm_next_scr(screenp)) {

        screen = *screenp;
        if (screen->data) {
            CHAR	**p;

            for (p = (CHAR **)firstArrayItemp(screen->data); 
                 p && *p; 
                 p = (CHAR **)nextArrayItemp(screen->data, (void **)p)) {
                sm_data_to_screen(screen, *p, 0);
                sm_screen_to_data(*p, screen);
            }
        }
    }

    store_files(0);
    
    sm_term();
    return(0);
}

/* For emacs:
 * Local Variables:
 * tab-width: 8
 * End:
 */
